package part2.miniTomcat;

import lombok.extern.slf4j.Slf4j;
import part2.miniTomcat.request.Request;
import part2.miniTomcat.request.Response;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author 大忽悠
 * @create 2022/9/1 9:28
 */
@Slf4j
public class Server {
    /**
     * 当前WEB项目的根目录
     */
    public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "web-app";

    /**
     * 停止服务器的命令
     */
    private static final String SHUTDOWN_COMMAND = "/shutdown";

    /**
     * 默认启动端口
     */
    private static final Integer DEFAULT_PORT = 8080;

    /**
     * 停止信号的是否发出
     */
    private boolean shutdown = false;

    /**
     * 服务器监听端口号
     */
    private Integer port = DEFAULT_PORT;

    /**
     * 服务端等待队列最大连接数
     */
    private Integer backLog = 1;

    public void start() {
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port, backLog, InetAddress.getByName("127.0.0.1"));
            log.info("miniTomcat在{}端口启动,客户端最大连接数被设置为{}", port, backLog);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        //轮询监听客户端请求
        while (!shutdown) {
            Socket client = null;
            try {
                client = serverSocket.accept();
                log.info("客户端[{}]请求正在被处理...", client.getRemoteSocketAddress());
                OutputStream out = client.getOutputStream();
                InputStream in = client.getInputStream();

                log.info("请求解析中....");
                Request request = new Request(in);
                request.parse();

                log.info("发送响应中....");
                Response response = new Response(out);
                response.setRequest(request);

                //区分资源类型
                if (request.getUri().startsWith("/servlet/")) {
                    //servlet请求资源处理
                    ServletProcessor processor = new ServletProcessor();
                    processor.process(request, response);
                } else {
                    //静态资源请求
                    StaticResourceProcessor processor = new StaticResourceProcessor();
                    processor.processor(request, response);
                }

                //本次客户端连接处理结束
                client.close();

                //检查是否是关闭服务器请求
                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void setShutdown(boolean shutdown) {
        this.shutdown = shutdown;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    /**
     * <p>backlog:</p>
     * <p>服务端socket处理客户端socket连接是需要一定时间的。 </p>
     * <p>ServerSocket有一个队列，存放还没有来得及处理的客户端Socket，这个队列的容量就是backlog的含义。 </p>
     * <p>如果队列已经被客户端socket占满了，如果还有新的连接过来，那么ServerSocket会拒绝新的连接。 </p>
     * <p>也就是说backlog提供了容量限制功能，避免太多的客户端socket占用太多服务器资源。 </p>
     * <p>客户端每次创建一个Socket对象，服务端的队列长度就会增加1个 ---> new Socket("127.0.0.1", 8888); </p>
     * <p>服务端每次accept()，就会从队列中取出一个元素 ---> Socket client = server.accept(); </p>
     */
    public void setBackLog(Integer backLog) {
        this.backLog = backLog;
    }
}
